package com.onstar.cn.weight;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;

/**
 * Created by 6335yz on 2016/5/27.
 */
public class RoundProgress extends View {
    private RectF circleOuter;
    private RectF circleInner;
    private Paint paintOuter;
    private Paint paintInner;

    private float OUTER_START_POINT_X = dp2px(10);
    private float OUTER_START_POINT_Y = dp2px(10);
    private float INNER_START_POINT_X = dp2px(20);
    private float INNER_START_POINT_Y = dp2px(20);
    private float OUTER_RADIUS = dp2px(45);
    private float INNER_RADIUS = dp2px(25);
    private float paint_width;

    public static final int STROKE = 0;
    public static final int FILL = 1;
    private int style;//实心或空心
    private boolean wasCancelled = false;

    public RoundProgress(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

        Resources rs = getResources();
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.roundprogress);
        style = array.getInt(R.styleable.roundprogress_round_style, STROKE);
        round_animation = array.getInt(R.styleable.roundprogress_round_duration, rs.getInteger(R.integer.default_round_duration));
        paint_width = array.getDimensionPixelSize(R.styleable.roundprogress_round_width, rs.getDimensionPixelSize(R.dimen.round_width));
        array.recycle();

        circleOuter = new RectF(OUTER_START_POINT_X, OUTER_START_POINT_Y, OUTER_START_POINT_X + OUTER_RADIUS, OUTER_START_POINT_Y + OUTER_RADIUS);
        circleInner = new RectF(INNER_START_POINT_X, INNER_START_POINT_Y, INNER_START_POINT_X + INNER_RADIUS, INNER_START_POINT_Y + INNER_RADIUS);

        paintOuter = new Paint();
        paintInner = new Paint();

        paintInner.setColor(getResources().getColor(R.color.inner_circle));
        paintOuter.setColor(getResources().getColor(R.color.outer_circle));

        paintInner.setAntiAlias(true);
        paintOuter.setAntiAlias(true);

        paintInner.setStrokeWidth(paint_width);
        paintOuter.setStrokeWidth(paint_width);
        if (style == STROKE) {
            paintInner.setStyle(Paint.Style.STROKE);
            paintOuter.setStyle(Paint.Style.STROKE);
        } else {
            paintInner.setStyle(Paint.Style.FILL);
            paintOuter.setStyle(Paint.Style.FILL);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(getResources().getColor(R.color.back_circle));
        canvas.drawArc(circleOuter, startAngle + indeterminateRotateOffset, indeterminateSweep, false, paintOuter);
        canvas.drawArc(circleInner, -(startAngle + indeterminateRotateOffset), -indeterminateSweep, false, paintInner);
    }


    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                getResources().getDisplayMetrics());
    }

    private void resetAnimation() {
        indeterminateSweep = INDETERMINANT_MIN_SWEEP;
        // Build the whole AnimatorSet
        indeterminateAnimator = new AnimatorSet();
        AnimatorSet prevSet = null, nextSet;
        for (int k = 0; k < animSteps; k++) {
            nextSet = createIndeterminateAnimator(k);
            AnimatorSet.Builder builder = indeterminateAnimator.play(nextSet);
            if (prevSet != null)
                builder.after(prevSet);
            prevSet = nextSet;
        }

        // Listen to end of animation so we can infinitely loop
        indeterminateAnimator.addListener(new AnimatorListenerAdapter() {


            @Override
            public void onAnimationCancel(Animator animation) {
                wasCancelled = true;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!wasCancelled)
                    resetAnimation();
            }
        });
        indeterminateAnimator.start();
    }

    private AnimatorSet indeterminateAnimator;
    private float startAngle;
    private int round_animation;
    private int animSteps = 3;
    private float indeterminateSweep, indeterminateRotateOffset;
    private static final float INDETERMINANT_MIN_SWEEP = 15f;

    // Creates the animators for one step of the animation
    private AnimatorSet createIndeterminateAnimator(float step) {
        final float maxSweep = 360f * (animSteps - 1) / animSteps + INDETERMINANT_MIN_SWEEP;
        final float start = -90f + step * (maxSweep - INDETERMINANT_MIN_SWEEP);

        // Extending the front of the arc
        ValueAnimator frontEndExtend = ValueAnimator.ofFloat(INDETERMINANT_MIN_SWEEP, maxSweep);
        frontEndExtend.setDuration(round_animation / animSteps / 2);
        frontEndExtend.setInterpolator(new DecelerateInterpolator(1));
        frontEndExtend.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                indeterminateSweep = (Float) animation.getAnimatedValue();
//                Log.d("Roundani", "滑过的弧度 = " + indeterminateSweep);
                invalidate();
            }
        });

        // Overall rotation
        ValueAnimator rotateAnimator1 = ValueAnimator.ofFloat(step * 720f / animSteps, (step + .5f) * 720f / animSteps);
        rotateAnimator1.setDuration(round_animation / animSteps / 2);
        rotateAnimator1.setInterpolator(new LinearInterpolator());
        rotateAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                indeterminateRotateOffset = (Float) animation.getAnimatedValue();
//                Log.d("Roundani", "起始角度1 = " + indeterminateRotateOffset);
            }
        });

        // Followed by...

        // Retracting the back end of the arc
        ValueAnimator backEndRetract = ValueAnimator.ofFloat(start, start + maxSweep - INDETERMINANT_MIN_SWEEP);
        backEndRetract.setDuration(round_animation / animSteps / 2);
        backEndRetract.setInterpolator(new DecelerateInterpolator(1));
        backEndRetract.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                startAngle = (Float) animation.getAnimatedValue();
                indeterminateSweep = maxSweep - startAngle + start;
                invalidate();
            }
        });

        // More overall rotation
        ValueAnimator rotateAnimator2 = ValueAnimator.ofFloat((step + .5f) * 720f / animSteps, (step + 1) * 720f / animSteps);
        rotateAnimator2.setDuration(round_animation / animSteps / 2);
        rotateAnimator2.setInterpolator(new LinearInterpolator());
        rotateAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                indeterminateRotateOffset = (Float) animation.getAnimatedValue();
//                Log.d("Roundani", "起始角度2 = " + indeterminateRotateOffset);
            }
        });

        AnimatorSet set = new AnimatorSet();
        set.play(frontEndExtend).with(rotateAnimator1);
        set.play(backEndRetract).with(rotateAnimator2).after(frontEndExtend);
        return set;
    }

    public void stopAnimation() {
        if (indeterminateAnimator != null) {
            indeterminateAnimator.cancel();
            indeterminateAnimator = null;
            wasCancelled = true;
        }
    }

    public void startAnimation() {
        wasCancelled = false;
        resetAnimation();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startAnimation();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopAnimation();
    }

    @Override
    public void setVisibility(int visibility) {
        int currentVisibility = getVisibility();
        super.setVisibility(visibility);
        if (visibility != currentVisibility) {
            if (visibility == View.VISIBLE) {
                startAnimation();
            } else if (visibility == View.GONE || visibility == View.INVISIBLE) {
                stopAnimation();
            }
        }
    }
}
